package com.dlc.shop.service.impl;


import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.dlc.shop.bean.dto.FlowAnalysisDto;
import com.dlc.shop.bean.dto.FlowUserAnalysisDto;
import com.dlc.shop.bean.enums.FlowTimeTypeEnum;
import com.dlc.shop.bean.enums.SystemEnum;
import com.dlc.shop.bean.param.FlowAnalysisParam;
import com.dlc.shop.bean.param.FlowUserAnalysisParam;
import com.dlc.shop.common.util.PoiExcelUtil;
import com.dlc.shop.service.AreaService;
import com.dlc.shop.service.FlowUserAnalysisExcelService;
import com.dlc.shop.service.FlowUserAnalysisService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 *
 *
 * @author YXF
 * @date 2020-07-17 09:50:13
 */
@Slf4j
@Service
@AllArgsConstructor
public class FlowUserAnalysisExcelServiceImpl implements FlowUserAnalysisExcelService {

    private final FlowUserAnalysisService flowUserAnalysisService;
    private final AreaService areaService;

    @Override
    public void analysisDataExport(FlowAnalysisParam flowAnalysisParam, HttpServletResponse response) {
        // 存入excel中
        //通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getBigWriter();
        // 商品导出or模板
        String[] headerArray = {"", "全部", "PC", "H5", "微信小程序", "安卓", "ios"};
        List<String> headerList = Arrays.asList(headerArray);
        writer.merge(headerList.size() - 1, "流量分析信息");
        writer.writeRow(headerList);
        setSheet(writer, headerList.size() - 1, 15);
        // 获取数据
        flowAnalysisParam.setSystemType(0);
        FlowAnalysisDto all = flowUserAnalysisService.getFlowAnalysisData(flowAnalysisParam);
        flowAnalysisParam.setSystemType(1);
        FlowAnalysisDto pc = flowUserAnalysisService.getFlowAnalysisData(flowAnalysisParam);
        flowAnalysisParam.setSystemType(2);
        FlowAnalysisDto h5 = flowUserAnalysisService.getFlowAnalysisData(flowAnalysisParam);
        flowAnalysisParam.setSystemType(3);
        FlowAnalysisDto weChat = flowUserAnalysisService.getFlowAnalysisData(flowAnalysisParam);
        flowAnalysisParam.setSystemType(4);
        FlowAnalysisDto android = flowUserAnalysisService.getFlowAnalysisData(flowAnalysisParam);
        flowAnalysisParam.setSystemType(5);
        FlowAnalysisDto ios = flowUserAnalysisService.getFlowAnalysisData(flowAnalysisParam);
        int row = 0;
        // 写入数据

        writeSysAnalysisData(writer, "访客数", all.getUserNums(), pc.getUserNums(), h5.getUserNums(), weChat.getUserNums(), android.getUserNums(), ios.getUserNums(), ++row);
        writeSysAnalysisData(writer, "浏览量", all.getVisitNums(), pc.getVisitNums(), h5.getVisitNums(), weChat.getVisitNums(), android.getVisitNums(), ios.getVisitNums(), ++row);
        writeSysAnalysisData(writer, "人均浏览量", all.getAverageVisitNums(), pc.getAverageVisitNums(), h5.getAverageVisitNums(), weChat.getAverageVisitNums(), android.getAverageVisitNums(), ios.getAverageVisitNums(), ++row);
        writeSysAnalysisData(writer, "支付人数", all.getPayUser(), pc.getPayUser(), h5.getPayUser(), weChat.getPayUser(), android.getPayUser(), ios.getPayUser(), ++row);
        if (!Objects.equals(flowAnalysisParam.getTimeType(), FlowTimeTypeEnum.REAL_TIME.value())) {
            writeSysAnalysisData(writer, "新访客数", all.getNewUser(), pc.getNewUser(), h5.getNewUser(), weChat.getNewUser(), android.getNewUser(), ios.getNewUser(), ++row);
            writeSysAnalysisData(writer, "平均停留时长(秒)", all.getAverageStopTime(), pc.getAverageStopTime(), h5.getAverageStopTime(), weChat.getAverageStopTime(), android.getAverageStopTime(), ios.getAverageStopTime(), ++row);
            writeSysAnalysisData(writer, "跳失率", all.getLossUserRate(), pc.getLossUserRate(), h5.getLossUserRate(), weChat.getLossUserRate(), android.getLossUserRate(), ios.getLossUserRate(), ++row);
            writeSysAnalysisData(writer, "访问-支付转化率", all.getPayRate(), pc.getPayRate(), h5.getPayRate(), weChat.getPayRate(), android.getPayRate(), ios.getPayRate(), ++row);
        }
        PoiExcelUtil.writeExcel(response, writer);
    }

    @Override
    public void flowTrendExport(FlowAnalysisParam flowAnalysisParam, HttpServletResponse response) {
        // 存入excel中
        //通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getWriterWithSheet("全部");
        // 商品导出or模板
        flowAnalysisParam.setSystemType(0);

        writeFlowTrendData(flowAnalysisParam, writer);

        // pc、h5、微信小程序、安卓、ios
        for (SystemEnum systemEnum : SystemEnum.values()) {
            writer = writer.setSheet(systemEnum.getName());
            flowAnalysisParam.setSystemType(systemEnum.value());
            writeFlowTrendData(flowAnalysisParam, writer);
        }

        PoiExcelUtil.writeExcel(response, writer);
    }

    @Override
    public void flowSour(FlowAnalysisParam flowAnalysisParam, HttpServletResponse response) {
        // 存入excel中
        //通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getBigWriter();
        // 商品导出or模板
        String[] headerArray = {"", "PC", "H5", "微信小程序", "安卓", "ios"};
        List<String> headerList = Arrays.asList(headerArray);
        writer.merge(headerList.size() - 1, "会员人数趋势信息");
        writer.writeRow(headerList);
        setSheet(writer, headerList.size() -1, 20);

        List<FlowAnalysisDto> flowAnalysisDtoList = flowUserAnalysisService.flowSour(flowAnalysisParam);
        Map<Integer, FlowAnalysisDto> flowAnalysisMap = flowAnalysisDtoList.stream().collect(Collectors.toMap(FlowAnalysisDto::getSystemType, f -> f));
        FlowAnalysisDto pc = flowAnalysisMap.containsKey(SystemEnum.PC.value()) ? flowAnalysisMap.get(SystemEnum.PC.value()) : new FlowAnalysisDto();
        FlowAnalysisDto h5 = flowAnalysisMap.containsKey(SystemEnum.H5.value()) ? flowAnalysisMap.get(SystemEnum.H5.value()) : new FlowAnalysisDto();
        FlowAnalysisDto weChat = flowAnalysisMap.containsKey(SystemEnum.APPLETS.value()) ? flowAnalysisMap.get(SystemEnum.APPLETS.value()) : new FlowAnalysisDto();
        FlowAnalysisDto android = flowAnalysisMap.containsKey(SystemEnum.ANDROID.value()) ? flowAnalysisMap.get(SystemEnum.ANDROID.value()) : new FlowAnalysisDto();
        FlowAnalysisDto ios = flowAnalysisMap.containsKey(SystemEnum.IOS.value()) ? flowAnalysisMap.get(SystemEnum.IOS.value()) : new FlowAnalysisDto();
        int row = 0;
        writeFlowSour(writer, "访客数占比", pc.getUserNumsRatio(), h5.getUserNumsRatio(), weChat.getUserNumsRatio(), android.getUserNumsRatio(), ios.getUserNumsRatio(), ++row);
        writeFlowSour(writer, "访客数", pc.getUserNums(), h5.getUserNums(), weChat.getUserNums(), android.getUserNums(), ios.getUserNums(), ++row);
        writeFlowSour(writer, "UV价值", pc.getUvPrice(), h5.getUvPrice(), weChat.getUvPrice(), android.getUvPrice(), ios.getUvPrice(), ++row);
        writeFlowSour(writer, "加购人数", pc.getPlusShopCartUser(), h5.getPlusShopCartUser(), weChat.getPlusShopCartUser(), android.getPlusShopCartUser(), ios.getPlusShopCartUser(), ++row);
        writeFlowSour(writer, "下单人数", pc.getPlaceOrderUser(), h5.getPlaceOrderUser(), weChat.getPlaceOrderUser(), android.getPlaceOrderUser(), ios.getPlaceOrderUser(), ++row);
        writeFlowSour(writer, "下单金额", pc.getPlaceOrderAmount(), h5.getPlaceOrderAmount(), weChat.getPlaceOrderAmount(), android.getPlaceOrderAmount(), ios.getPlaceOrderAmount(), ++row);
        writeFlowSour(writer, "访问-下单转化率", pc.getPlaceOrderRate(), h5.getPlaceOrderRate(), weChat.getPlaceOrderRate(), android.getPlaceOrderRate(), ios.getPlaceOrderRate(), ++row);
        writeFlowSour(writer, "支付人数", pc.getPayUser(), h5.getPayUser(), weChat.getPayUser(), android.getPayUser(), ios.getPayUser(), ++row);
        writeFlowSour(writer, "支付金额", pc.getPayAmount(), h5.getPayAmount(), weChat.getPayAmount(), android.getPayAmount(), ios.getPayAmount(), ++row);
        writeFlowSour(writer, "访问-支付转化率", pc.getPayRate(), h5.getPayRate(), weChat.getPayRate(), android.getPayRate(), ios.getPayRate(), ++row);
        writeFlowSour(writer, "客单价", pc.getCustomerPrice(), h5.getCustomerPrice(), weChat.getCustomerPrice(), android.getCustomerPrice(), ios.getCustomerPrice(), ++row);

        PoiExcelUtil.writeExcel(response, writer);
    }

    @Override
    public void userAnalysisDataExport(FlowUserAnalysisParam flowUserAnalysisParam, HttpServletResponse response) {
        flowUserAnalysisService.getUserAnalysisData(flowUserAnalysisParam);
        List<FlowUserAnalysisDto> visitUserList = flowUserAnalysisParam.getVisitUserList();
        // 存入excel中
        //通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getBigWriter();
        // 商品导出or模板
        String[] headerArray = {"地区", "浏览量", "访客数", "商品浏览量", "页面总停留时长"};
        List<String> headerList = Arrays.asList(headerArray);
        writer.merge(headerList.size() - 1, "会员地域分布信息");
        writer.writeRow(headerList);
        setSheet(writer, headerList.size() -1, 20);
        int row = 1;

        for (FlowUserAnalysisDto flowUserAnalysisDto : visitUserList) {
            int col = -1;
            PoiExcelUtil.mergeIfNeed(writer, ++row, row, ++col, col, flowUserAnalysisDto.getProvinceName());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, flowUserAnalysisDto.getVisitNums());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, flowUserAnalysisDto.getVisitUser());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, flowUserAnalysisDto.getProdVisitNums());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, flowUserAnalysisDto.getStopTime());
        }
        PoiExcelUtil.writeExcel(response, writer);
    }

    private int writeFlowTrendData(FlowAnalysisParam flowAnalysisParam, ExcelWriter writer) {
        String[] headerArray = {"日期", "访客数", "新访客数", "浏览量", "平均停留时长(秒)", "人均浏览量", "跳失率", "支付人数", "访问-支付转化率"};
        List<String> headerList = Arrays.asList(headerArray);
        writer.merge(headerList.size() - 1, "流量趋势信息");
        writer.writeRow(headerList);
        setSheet(writer, headerList.size() -1, 20);

        int row = 1;
        boolean isMerge = Objects.equals(flowAnalysisParam.getTimeType(), FlowTimeTypeEnum.REAL_TIME.value());
        List<FlowAnalysisDto> list = flowUserAnalysisService.flowTrend(flowAnalysisParam);
        for (FlowAnalysisDto flowAnalysisDto : list) {
            int col = -1;

            PoiExcelUtil.mergeIfNeed(writer, ++row, row, ++col, col, flowAnalysisDto.getDateTime());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, flowAnalysisDto.getUserNums());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, isMerge ? 0 : flowAnalysisDto.getNewUser());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, flowAnalysisDto.getVisitNums());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, isMerge ? 0 : flowAnalysisDto.getAverageStopTime());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, flowAnalysisDto.getAverageVisitNums());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, isMerge ? 0 : flowAnalysisDto.getLossUserRate());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, flowAnalysisDto.getPayUser());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, flowAnalysisDto.getPayRate() * 100);
        }
        return row;
    }


    private void writeSysAnalysisData(ExcelWriter writer, String name, Object all, Object pc, Object h5, Object weChat, Object android, Object ios, int row) {
        int col = -1;
        PoiExcelUtil.mergeIfNeed(writer, ++row, row, ++col, col, name);
        PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, all);
        PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, pc);
        PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, h5);
        PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, weChat);
        PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, android);
        PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, ios);
    }


    private void writeFlowSour(ExcelWriter writer, String name, Object pc, Object h5, Object weChat, Object android, Object ios, int row) {
        int col = -1;
        PoiExcelUtil.mergeIfNeed(writer, ++row, row, ++col, col, name);
        PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, Objects.nonNull(pc) ? pc : 0);
        PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, Objects.nonNull(h5) ? h5 : 0);
        PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, Objects.nonNull(weChat) ? weChat : 0);
        PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, Objects.nonNull(android) ? android : 0);
        PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, Objects.nonNull(ios) ? ios : 0);
    }

    private void setSheet(ExcelWriter writer, Integer num, Integer width) {
        if (Objects.isNull(width) || width < 0) {
            width = 20;
        }
        Sheet sheet = writer.getSheet();
        for (int i = 0; i <= num; i++) {
            sheet.setColumnWidth(i, width * 256);
        }

    }
}
